﻿#region Imported Libraries
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using org.webguvenligi.NSecureImageLib.GraphicFileFormats.Utilities;
#endregion
namespace org.webguvenligi.NSecureImageLib.GraphicFileFormats.JPEG
{
    public abstract class JPEGBaseChunk
    {
        
        public ushort SegmentLength
        {
            get;
            private set;
        }
        public string SegmentName
        {
            get;
            private set;
        }
        public byte[] SegmentBody
        {
            get;
            private set;
        }
        protected JPEGBaseChunk(BinaryReader imageReader,
                                ushort segmentLength,
                                string segmentName)
        {
            this.SegmentLength = segmentLength;
            imageReader.EnsureBytes(segmentLength);            
            this.SegmentName = segmentName;
            ExtractBodyFromStream(imageReader, segmentLength);
        }

        protected virtual void ExtractBodyFromStream(BinaryReader imageReader,
                                                     ushort segmentLength)
        {
            this.SegmentBody = imageReader.ReadBytes(segmentLength);
            MemoryStream bodyStream =
                new MemoryStream(this.SegmentBody);
            bodyStream.Position = 0;
            using (BinaryReader segmentReader = new BinaryReader(bodyStream))
            {
                ParseContent(segmentReader);
            }
        }
        
        protected abstract void ParseContent(BinaryReader contentReader);

        public static List<JPEGBaseChunk> CleanChunks(BinaryReader imageReader,
                                                      BinaryWriter imageWriter)
        {
            List<JPEGBaseChunk> fullChunkList =
                new List<JPEGBaseChunk>();

            MemoryStream markerStream = new MemoryStream();

            while (imageReader.BytesRemaining() > 0)
            {
                imageReader.EnsureBytes(2);
                ushort possibleMarkerCode = 
                    imageReader.ReadLittleEndianUInt16();
                imageWriter.WriteLittleEndian(possibleMarkerCode);                
                if (Enum.IsDefined(typeof(JPEGMarkerCodes), (uint)possibleMarkerCode))
                {
                    
                    JPEGBaseChunk tempChunk = null;
                    
                    string segmentName =
                        Enum.GetName(typeof(JPEGMarkerCodes), possibleMarkerCode);
                    
                    ushort segmentLength = 0;

                    if (((JPEGMarkerCodes)(int)possibleMarkerCode)
                        != JPEGMarkerCodes.EOI)
                    {
                        imageReader.EnsureBytes(2);
                        segmentLength =
                            imageReader.ReadLittleEndianUInt16();
                        segmentLength -= 2;
                        imageReader.EnsureBytes(segmentLength);
                    }

                    switch ((JPEGMarkerCodes)(int)possibleMarkerCode)
                    {
                        case JPEGMarkerCodes.APP0:
                            //tempChunk =
                            //    new JpegChunkAPP0(imageReader,
                            //                      segmentLength,
                            //                      segmentName);
                            break;
                        case JPEGMarkerCodes.APP1:
                            //tempChunk =
                            //    new JpegChunkAPP1(imageReader,
                            //                      segmentLength,
                            //                      segmentName);
                            break;
                        case JPEGMarkerCodes.SOS:
                            //tempChunk =
                            //    new JpegChunkSOS(imageReader,
                            //                     segmentLength,
                            //                     segmentName);
                            break;
                        default:
                            //tempChunk = new JPEGUnknownChunk(imageReader,
                            //                     segmentLength,
                            //                     segmentName);
                            break;
                    }
                    System.Diagnostics.Debug.WriteLine(tempChunk.SegmentName);
                    if (tempChunk != null)
                        fullChunkList.Add(tempChunk);
                }
                else
                {
                    break;
                }
            }
            return fullChunkList;
        }

        //TODO Refactor This Methods
        public static List<JPEGBaseChunk> GetChunks(BinaryReader imageReader)
        {
            List<JPEGBaseChunk> fullChunkList =
                new List<JPEGBaseChunk>();
            
            MemoryStream markerStream = new MemoryStream();

            while (imageReader.BytesRemaining() > 0)
            {
                    imageReader.EnsureBytes(2);
                    ushort possibleMarkerCode = imageReader.ReadLittleEndianUInt16();
                    if (Enum.IsDefined(typeof(JPEGMarkerCodes), (uint)possibleMarkerCode))
                    {
                        JPEGBaseChunk tempChunk = null;
                        string segmentName = 
                            Enum.GetName(typeof(JPEGMarkerCodes), possibleMarkerCode);
                        ushort segmentLength = 0;
                        
                        if (((JPEGMarkerCodes)(int)possibleMarkerCode) 
                            != JPEGMarkerCodes.EOI)
                        {
                            imageReader.EnsureBytes(2);
                            segmentLength =
                                imageReader.ReadLittleEndianUInt16();
                            segmentLength -= 2;
                            imageReader.EnsureBytes(segmentLength);
                        }

                        switch ((JPEGMarkerCodes)(int)possibleMarkerCode)
                        {
                            case JPEGMarkerCodes.APP0:
                                tempChunk = 
                                    new JpegChunkAPP0(imageReader,
                                                      segmentLength,
                                                      segmentName);
                                break;
                            case JPEGMarkerCodes.APP1:
                                tempChunk =
                                    new JpegChunkAPP1(imageReader,
                                                      segmentLength,
                                                      segmentName);
                                break;
                            case JPEGMarkerCodes.SOS:
                                tempChunk =
                                    new JpegChunkSOS(imageReader,
                                                     segmentLength,
                                                     segmentName);
                                break;
                            default:
                                tempChunk = new JPEGUnknownChunk(imageReader,
                                                     segmentLength,
                                                     segmentName);
                            break;
                        }
                        System.Diagnostics.Debug.WriteLine(tempChunk.SegmentName);
                        if (tempChunk != null)
                            fullChunkList.Add(tempChunk);
                    }
                    else
                    {
                        break;
                    }
            }
            return fullChunkList;
        }
    }
}